<?
/**
 * @author    徐鹏程 <xupengcheng@snda.com>
 * @version   0.0.1		2010/03/29
 */

include_once(dirname(__FILE__).'/UCLibCache.php');
include_once(dirname(__FILE__).'/oauth/OAuth.php');
require_once(dirname(__FILE__).'/UCLibPDOFactory.php');
require_once(dirname(__FILE__).'/../config/UCConfOAuth.php');

define("GRAPH_USING_MEMCACHE", 1);
define('UC_GRAPH_CHANNEL_NAME','graph'); //memcache分配的频道名
define('UC_GRAPH_MEMCACHE_EXPIRE', 600); //memcache过期时间

class UCLibOAuth {
	static $_server = null;

	static $_consumer = null;
	static $_access_token = null;

	static function getServer() {
		if (!self::$_server) {
			self::$_server = new SDOOAuthServer(new SDOOAuthDataStore());	
			$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
			$plaintext_method = new OAuthSignatureMethod_PLAINTEXT();
			$rsa_method = new SDOOAuthSignatureMethod_RSA_SHA1();

			self::$_server->add_signature_method($hmac_method);
			self::$_server->add_signature_method($plaintext_method);
			self::$_server->add_signature_method($rsa_method);
		}
		return self::$_server;
	}

	static function getRequestToken($token) {
		$server = self::getServer();
		return $server->get_data_store()->lookup_request_token($token);
	}

	static function authorizeRequestToken($token, $user_id, $pt_id) {
		$server = self::getServer();
		$requst_token = $server->get_data_store()->lookup_request_token($token);

		if ($requst_token) {
			$requst_token["user_id"] = $user_id;
			$requst_token["pt_id"] = $pt_id;
			$server->get_data_store()->set_request_token($requst_token);
			 return true;
		}
        return false;
	}
	
	static function unauthorizeRequestToken($token) {
		$server = self::getServer();
		$requst_token = $server->get_data_store()->delete_request_token($token);
	}

	static private function _check_request($need_access = true) {
		if (self::$_consumer) {
			if ($need_access && !self::$_access_token) {
				throw new OAuthException("Invalid signature");
			}
		}

		$request = OAuthRequest::from_request();
		if ($request->get_parameter("oauth_token")) {
			// 带有consumer和access token
			$server = self::getServer();
			$req = OAuthRequest::from_request();
			list($consumer, $token) = $server->verify_request($req);
			self::$_consumer = $consumer;
			self::$_access_token = $token;
		} else {
			if ($need_access) {
				throw new OAuthException("Invalid signature");
			}
			// 只有consumer
			$server = self::getServer();
			$consumer = $server->get_consumer($request);
			// 检查签名
			$server->check_signature($request, $consumer, NULL);
			self::$_consumer = $consumer;
			self::$_access_token = NULL;
		}
	}

	static function getAuthedUserId() {
		self::_check_request();
		return self::$_access_token->user_id;
	}

	static function getAuthedPtId() {
		self::_check_request();
		return self::$_access_token->pt_id;
	}

	static function getAppId() {
		self::_check_request(false);
		return self::$_consumer->app_id;
	}

	static function getConsumerKey() {
		self::_check_request(false);
		return self::$_consumer->key;
	}

	static function isInternalConsumer() {
		self::_check_request(false);
		return self::$_consumer->is_internal ? true : false;
	}

	static function destoryAccessToken() {
		self::_check_request();
		if (self::$_access_token && self::$_access_token->key) {
			$pdo = UCLibPDOFactory::getPDO(PDO_OAUTH_ACCESS_TOKEN, '', 'oauth2dbconfig');
			$pdo->query_with_prepare("delete from $pdo->database.$pdo->table where token=?",array(self::$_access_token->key));
		}
	}
}


class SDOOAuthServer extends OAuthServer {
  public function get_signature_methods() {
    return $this->signature_methods;
  }

  public function get_data_store() {
    return $this->data_store;
  }
}

class SDOOAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod_RSA_SHA1 {
  public function fetch_private_cert(&$request) {
    $cert = <<<EOD
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALRiMLAh9iimur8V
A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d
7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ
hI6GH4twrbDJCR2Bwy/XWXgqgGRzAgMBAAECgYBYWVtleUzavkbrPjy0T5FMou8H
X9u2AC2ry8vD/l7cqedtwMPp9k7TubgNFo+NGvKsl2ynyprOZR1xjQ7WgrgVB+mm
uScOM/5HVceFuGRDhYTCObE+y1kxRloNYXnx3ei1zbeYLPCHdhxRYW7T0qcynNmw
rn05/KO2RLjgQNalsQJBANeA3Q4Nugqy4QBUCEC09SqylT2K9FrrItqL2QKc9v0Z
zO2uwllCbg0dwpVuYPYXYvikNHHg+aCWF+VXsb9rpPsCQQDWR9TT4ORdzoj+Nccn
qkMsDmzt0EfNaAOwHOmVJ2RVBspPcxt5iN4HI7HNeG6U5YsFBb+/GZbgfBT3kpNG
WPTpAkBI+gFhjfJvRw38n3g/+UeAkwMI2TJQS4n8+hid0uus3/zOjDySH3XHCUno
cn1xOJAyZODBo47E+67R4jV1/gzbAkEAklJaspRPXP877NssM5nAZMU0/O/NGCZ+
3jPgDUno6WbJn5cqm8MqWhW1xGkImgRk+fkDBquiq4gPiT898jusgQJAd5Zrr6Q8
AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54
Lw03eHTNQghS0A==
-----END PRIVATE KEY-----
EOD;
    return $cert;
  }

  public function fetch_public_cert(&$request) {
    $cert = <<<EOD
-----BEGIN CERTIFICATE-----
MIIBpjCCAQ+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAZMRcwFQYDVQQDDA5UZXN0
IFByaW5jaXBhbDAeFw03MDAxMDEwODAwMDBaFw0zODEyMzEwODAwMDBaMBkxFzAV
BgNVBAMMDlRlc3QgUHJpbmNpcGFsMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQC0YjCwIfYoprq/FQO6lb3asXrxLlJFuCvtinTF5p0GxvQGu5O3gYytUvtC2JlY
zypSRjVxwxrsuRcP3e641SdASwfrmzyvIgP08N4S0IFzEURkV1wp/IpH7kH41Etb
mUmrXSwfNZsnQRE5SYSOhh+LcK2wyQkdgcMv11l4KoBkcwIDAQABMA0GCSqGSIb3
DQEBBQUAA4GBAGZLPEuJ5SiJ2ryq+CmEGOXfvlTtEL2nuGtr9PewxkgnOjZpUy+d
4TvuXJbNQc8f4AMWL/tO9w0Fk80rWKp9ea8/df4qMq5qlFWlx6yOLQxumNOmECKb
WpkUQDIDJEoFUzKMVuJf4KO/FJ345+BNLGgbJ6WujreoM1X/gYfdnJ/J
-----END CERTIFICATE-----
EOD;
    return $cert;
  }
}

/**
 * SDOOAuthToken 继承于OAuthToken
 * 多加入了user_id字段，用于标志授权的用户id
 */
class SDOOAuthToken extends OAuthToken {
	public $user_id = null;
	public $pt_id = null;

    function __construct($key, $secret, $user_id = NULL, $pt_id = NULL) {
		$this->user_id = $user_id;
		$this->pt_id = $pt_id;
		parent::__construct($key, $secret);
	}

	function to_string() {
		return json_encode(array("oauth_token" => $this->key, "oauth_token_secret" => $this->secret));
	}
}

/**
 * SDOOAuthConsumer 继承于OAuthConsumer
 * 多加入了app_id字段，用于标志对应的应用id
 */
class SDOOAuthConsumer extends OAuthConsumer {
	public $app_id = null;
	public $is_internal = false;

    function __construct($key, $secret, $app_id, $is_internal, $callback_url=NULL) {
		$this->app_id = $app_id;
		$this->is_internal = $is_internal;
		parent::__construct($key, $secret, $callback_url);
	}
}

/**
 * SDO Auth Data Store
 */
class SDOOAuthDataStore extends OAuthDataStore {

    function __construct() {
		require_once(dirname(__FILE__).'/UCLibGUID.php');
	}

    function lookup_consumer($consumer_key) {
		$pdo = UCLibPDOFactory::getPDO(PDO_OAUTH_CONSUMER, '', 'oauth2dbconfig');
		$row = $pdo-> query_one_row_with_prepare("select * from $pdo->database.$pdo->table where consumer_id=?",array($consumer_key));
		if ($row) {
			return new SDOOAuthConsumer($row["consumer_id"], $row["secret"], $row["app_id"], $row["is_internal"], NULL);
		}
        return NULL;
    }

	function lookup_request_token($token) {
		if (defined("GRAPH_USING_MEMCACHE")) {
			// 使用memcache存储request token
			require_once(dirname(__FILE__).'/UCLibCache.php');
			$cache = new UCLibCache(UC_GRAPH_CHANNEL_NAME, false);
			$key = "request.".$token;
			$result = $cache->read($key);
			if ($result) return json_decode($result, true);
		} else {
			// 使用数据库存储request token
			$pdo = UCLibPDOFactory::getPDO(PDO_OAUTH_REQUEST_TOKEN, '', 'oauth2dbconfig');
			$row = $pdo-> query_one_row_with_prepare("select * from $pdo->database.$pdo->table where token=?",array($token));
			if ($row) return $row;
		}
		return null;
	}

	function delete_request_token($token) {
		if (defined("GRAPH_USING_MEMCACHE")) {
			// 使用memcache存储request token
			require_once(dirname(__FILE__).'/UCLibCache.php');
			$cache = new UCLibCache(UC_GRAPH_CHANNEL_NAME, false);
			$key = "request.".$token;
			$cache->delete($key);
		} else {
			$pdo = UCLibPDOFactory::getPDO(PDO_OAUTH_REQUEST_TOKEN, '', 'oauth2dbconfig');
			$pdo-> exec_with_prepare("delete from $pdo->database.$pdo->table where token=?",array($token));
		}
		return null;
	}

	function set_request_token($token) {
		if (defined("GRAPH_USING_MEMCACHE")) {
			// 使用memcache存储request token
			require_once(dirname(__FILE__).'/UCLibCache.php');
			$cache = new UCLibCache(UC_GRAPH_CHANNEL_NAME, false);
			$key = "request.".$token["token"];
			$cache->write($key, json_encode($token), UC_GRAPH_MEMCACHE_EXPIRE);
		} else {
			$pdo = UCLibPDOFactory::getPDO(PDO_OAUTH_REQUEST_TOKEN, '', 'oauth2dbconfig');
			$pdo->insert($token);
		}
	}

    function lookup_token($consumer, $token_type, $token) {
		if ($token_type ==  "request") {
			$data = $this->lookup_request_token($token);
			if (!$data) return NULL;

			if ($data["consumer_id"] != $consumer->key) return NULL;
			return new SDOOAuthToken($data["token"], $data["secret"], $data["user_id"], $data["pt_id"]);

		} else if ($token_type ==  "access") {
			$pdo = UCLibPDOFactory::getPDO(PDO_OAUTH_ACCESS_TOKEN, '', 'oauth2dbconfig');
			$row = $pdo-> query_one_row_with_prepare("select * from $pdo->database.$pdo->table where consumer_id=? and token=?",array($consumer->key, $token));
			if ($row) {
				return new SDOOAuthToken($row["token"], $row["secret"], $row["user_id"], $row["pt_id"]);
			}
		}
        return NULL;
    }

    function lookup_nonce($consumer, $token, $nonce, $timestamp) {
        return NULL;
    }

    function new_request_token($consumer) {

		$token = md5(UCLibGUID::uuid32());
		$secret = md5(UCLibGUID::uuid32());
		$data = array("token" => $token, "secret" => $secret, "consumer_id" =>$consumer->key);
		$this->set_request_token($data);

		return new SDOOAuthToken($token, $secret);
    }

    function new_access_token($request_token, $consumer) {		
		$pdo = UCLibPDOFactory::getPDO(PDO_OAUTH_ACCESS_TOKEN, '', 'oauth2dbconfig');
		
		$row = $pdo->query_one_row_with_prepare("select * from $pdo->database.$pdo->table where consumer_id=? and user_id=? and pt_id=?",array($consumer->key, $request_token->user_id, $request_token->pt_id));

		$access_token = null;

		if ($row) {
			$access_token = new SDOOAuthToken($row["token"], $row["secret"]);
		} else {
			$token = md5($pdo->gen_uuid());
			$secret = md5($pdo->gen_uuid());
			$data = array("token" => $token, "secret" => $secret, "consumer_id" =>$consumer->key, "user_id"=>$request_token->user_id, "pt_id"=>$request_token->pt_id);
			$pdo->insert($data);
			$access_token = new SDOOAuthToken($token, $secret);
		}

		$this->delete_request_token($request_token->key);
		return $access_token;
    }
}
